/*
 *Copyright (c) [2019-2020]  C2comm, Inc.  All rights reserved.
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; If not, see <https://www.gnu.org/licenses/>
 */

/*
 *Vendor: C2comm
 *Version: 1.0
 *Filename: PCFClassify.v
 *Target Device: Altera
 *Author : 刘晓骏
*/


module PCFClassify(
    input  wire         SYS2CORE_clk,
    input  wire         SYS2CORE_rst_n,
    
    input  wire [336:0] CONF2CORE_cm_static_conf,
    
    input  wire         PPM2SCM_pcf_rx_cb_wr,
    input  wire [ 85:0] PPM2SCM_pcf_rx_cb,
    output wire         SCM2PPM_pcf_rx_cb_ready,
    
    output reg          PP2PD_pcf_rx_cb_wr,
    output reg  [ 85:0] PP2PD_pcf_rx_cb,
    input  wire         PD2PP_pcf_rx_cb_ready,
    
    output reg  [  3:0] PC2PAC_pcf_rx_cb_wr,
    output reg  [ 85:0] PC2PAC_pcf_rx_cb,
    input  wire [  3:0] PAC2PC_pcf_rx_cb_ready,
    
    input  wire [  3:0] PAC2PC_array_empty
);
/*//////////////////////////////////////////////////////////
                    中间变量声明区域
*///////////////////////////////////////////////////////////
//本模块中所有中间变量(wire/reg/parameter)在此集中声明 
//PcfCbBuffer信号
wire        pcbuffer_wrreq;
wire [85:0] pcbuffer_wdata;
reg         pcbuffer_wrack;

reg  [ 7:0] intcyc_type_reg[3:0];  

reg  [ 3:0] select_array_bit;

localparam  PCF_CS = 2'd0,
            PCF_CA = 2'd1,
            PCF_IN = 2'd2;  

reg [1:0] cls_state;

localparam  IDLE_S = 2'b01,
            WAIT_S = 2'b10;
/*//////////////////////////////////////////////////////////
                  转发分类(Forward Classify)
*///////////////////////////////////////////////////////////
always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        PP2PD_pcf_rx_cb_wr  <= 1'b0;
        PC2PAC_pcf_rx_cb_wr <= 4'b0;
        pcbuffer_wrack      <= 1'b0;
        select_array_bit    <= 4'b0;
        cls_state           <= IDLE_S;
    end
    else begin
        case(cls_state)
            IDLE_S:begin
                if(pcbuffer_wrreq == 1'b1) begin//有输入数据待转发
                    if((PD2PP_pcf_rx_cb_ready==1'b1) && 
                       ((pcbuffer_wdata[17:16]==PCF_CS)) || ((pcbuffer_wdata[17:16]==PCF_CA) &&(CONF2CORE_cm_static_conf[335] == 1'b1)))begin
                   
                        PP2PD_pcf_rx_cb_wr  <= 1'b1;
                        PC2PAC_pcf_rx_cb_wr <= 4'b0;
                        PP2PD_pcf_rx_cb     <= pcbuffer_wdata;
                        pcbuffer_wrack      <= 1'b1;
                        cls_state           <= IDLE_S;
                    end
                    else if((pcbuffer_wdata[17:16]==PCF_IN) || ((pcbuffer_wdata[17:16]==PCF_CA) && (CONF2CORE_cm_static_conf[336] == 1'b1))) begin
                  
                        PP2PD_pcf_rx_cb_wr <= 1'b0;
                        PC2PAC_pcf_rx_cb   <= pcbuffer_wdata;
                        if((PAC2PC_array_empty[0] == 1'b0) && 
                           (intcyc_type_reg[0]=={pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]})) begin
                      
                            select_array_bit    <= 4'b0001;
                            if(PAC2PC_pcf_rx_cb_ready[0] == 1'b1) begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0001;
                                pcbuffer_wrack      <= 1'b1;
                                cls_state           <= IDLE_S;
                            end
                            else begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0;
                                pcbuffer_wrack      <= 1'b0;
                                cls_state           <= WAIT_S;
                            end
                        end
                        else if((PAC2PC_array_empty[1] == 1'b0) && 
                                (intcyc_type_reg[1]=={pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]})) begin
                      
                            select_array_bit <= 4'b0010;
                            if(PAC2PC_pcf_rx_cb_ready[1] == 1'b1) begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0010;
                                pcbuffer_wrack      <= 1'b1;
                                cls_state           <= IDLE_S;
                            end
                            else begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0;
                                pcbuffer_wrack      <= 1'b0;
                                cls_state           <= WAIT_S;
                            end
                        end
                        else if((PAC2PC_array_empty[2] == 1'b0) && 
                                (intcyc_type_reg[2]=={pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]})) begin
                   
                            select_array_bit    <= 4'b0100;
                            if(PAC2PC_pcf_rx_cb_ready[2] == 1'b1) begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0100;
                                pcbuffer_wrack      <= 1'b1;
                                cls_state           <= IDLE_S;
                            end
                            else begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0;
                                pcbuffer_wrack      <= 1'b0;
                                cls_state           <= WAIT_S;
                            end
                        end
                        else if((PAC2PC_array_empty[3] == 1'b0) && 
                                (intcyc_type_reg[3]=={pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]})) begin
                   
                            select_array_bit    <= 4'b1000;
                            if(PAC2PC_pcf_rx_cb_ready[3] == 1'b1) begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b1000;
                                pcbuffer_wrack      <= 1'b1;
                                cls_state           <= IDLE_S;
                            end
                            else begin
                                PC2PAC_pcf_rx_cb_wr <= 4'b0;
                                pcbuffer_wrack      <= 1'b0;
                                cls_state           <= WAIT_S;
                            end
                        end
                        else if((PAC2PC_array_empty[0] == 1'b1) && ((PAC2PC_pcf_rx_cb_ready[0] == 1'b1))) begin
                       
                            select_array_bit    <= 4'b0001;
                            PC2PAC_pcf_rx_cb_wr <= 4'b0001;
                            pcbuffer_wrack      <= 1'b1;
                            intcyc_type_reg[0]  <= {pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]};
                            cls_state           <= IDLE_S;
                        end
                        else if((PAC2PC_array_empty[1] == 1'b1) && ((PAC2PC_pcf_rx_cb_ready[1] == 1'b1))) begin
                          
                            select_array_bit    <= 4'b0010;
                            PC2PAC_pcf_rx_cb_wr <= 4'b0010;
                            pcbuffer_wrack      <= 1'b1;
                            intcyc_type_reg[1]  <= {pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]};
                            cls_state           <= IDLE_S;
                        end
                        else if((PAC2PC_array_empty[2] == 1'b1) && ((PAC2PC_pcf_rx_cb_ready[2] == 1'b1))) begin
                           
                            select_array_bit    <= 4'b0100;
                            PC2PAC_pcf_rx_cb_wr <= 4'b0100;
                            pcbuffer_wrack      <= 1'b1;
                            intcyc_type_reg[2]  <= {pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]};
                            cls_state           <= IDLE_S;
                        end
                        else if((PAC2PC_array_empty[3] == 1'b1) && ((PAC2PC_pcf_rx_cb_ready[3] == 1'b1))) begin
                            
                            select_array_bit    <= 4'b1000;
                            PC2PAC_pcf_rx_cb_wr <= 4'b1000;
                            pcbuffer_wrack      <= 1'b1;
                            intcyc_type_reg[3]  <= {pcbuffer_wdata[17:16],pcbuffer_wdata[7:2]};
                            cls_state           <= IDLE_S;
                        end
                        else begin
                           
                            select_array_bit    <= 4'b0;
                            PC2PAC_pcf_rx_cb_wr <= 4'b0;  
                            pcbuffer_wrack      <= 1'b0;
                            cls_state           <= IDLE_S;
                        end
                    end
                    else begin
                    //虽然有数据，但是两个输出端都无法接收，因此需要继续等待
                        select_array_bit    <= 4'b0;
                        PP2PD_pcf_rx_cb_wr  <= 1'b0;
                        PC2PAC_pcf_rx_cb_wr <= 4'b0;
                        pcbuffer_wrack      <= 1'b0;
                        cls_state           <= IDLE_S;
                    end
                end
                else begin
                    select_array_bit    <= 4'b0;
                    PP2PD_pcf_rx_cb_wr  <= 1'b0;
                    PC2PAC_pcf_rx_cb_wr <= 4'b0;
                    pcbuffer_wrack      <= 1'b0;
                    cls_state           <= IDLE_S;
                end
            end
            
            WAIT_S: begin
                if((|(select_array_bit & PAC2PC_pcf_rx_cb_ready)) == 1'b1) begin
                    select_array_bit    <= 4'b0;
                    PC2PAC_pcf_rx_cb_wr <= select_array_bit;
                    pcbuffer_wrack      <= 1'b1;
                    cls_state           <= IDLE_S;
                end
                else begin
                    PC2PAC_pcf_rx_cb_wr <= 4'b0;
                    pcbuffer_wrack      <= 1'b0;
                    cls_state           <= WAIT_S;
                end
            end
            
            default: begin
                PP2PD_pcf_rx_cb_wr  <= 1'b0;
                PC2PAC_pcf_rx_cb_wr <= 4'b0;
                pcbuffer_wrack      <= 1'b0;
                select_array_bit    <= 4'b0;
                cls_state           <= IDLE_S;
            end
        endcase
    end
end


/*//////////////////////////////////////////////////////////
                   IP调用区域
*///////////////////////////////////////////////////////////
//本模块调用的所有IP在该区域实例化
//例如fifo/ram/grant之类的IP.... 
InportBuffer #(
    .DWIDTH(86)
)PcfCbBuffer(
    .clk(SYS2CORE_clk),
    .rst_n(SYS2CORE_rst_n),

    .idata_valid(PPM2SCM_pcf_rx_cb_wr),
    .idata(PPM2SCM_pcf_rx_cb),
    .idata_ready(SCM2PPM_pcf_rx_cb_ready),

    .odata_wrreq(pcbuffer_wrreq),
    .odata(pcbuffer_wdata),
    .odata_wrack(pcbuffer_wrack)
);
endmodule
/*
PCFClassify PCFClassify_inst(
    .SYS2CORE_clk(),
    .SYS2CORE_rst_n(),

    .CONF2CORE_cm_static_conf(),

    .PPM2SCM_pcf_rx_cb_wr(),
    .PPM2SCM_pcf_rx_cb(),
    .SCM2PPM_pcf_rx_cb_ready(),

    .PP2PD_pcf_rx_cb_wr(),
    .PP2PD_pcf_rx_cb(),
    .PD2PP_pcf_rx_cb_ready(),

    .PC2PAC_pcf_rx_cb_wr(),
    .PC2PAC_pcf_rx_cb(),
    .PAC2PC_pcf_rx_cb_ready(),

    .PAC2PC_array_empty()
);
*/